Skip to content

fix: resolve Claude CLI not found on Windows - PATH, prompt size, cwd (#1661)#1843

Merged
AndyMik90 merged 8 commits intodevelopfrom
fix/1661-claude-code-not-found
Feb 18, 2026
Merged

fix: resolve Claude CLI not found on Windows - PATH, prompt size, cwd (#1661)#1843
AndyMik90 merged 8 commits intodevelopfrom
fix/1661-claude-code-not-found

Conversation

@AndyMik90
Copy link
Owner

@AndyMik90 AndyMik90 commented Feb 15, 2026

Summary

Fixes three root causes behind "Claude code not found" errors on Windows Kanban tasks (#1661):

  • PATH overwrite: pythonEnv.PATH (containing only pywin32_system32) was spread after the augmented env.PATH (containing npm globals, Homebrew, etc.), overwriting it. Now merges PATH entries instead - prepends python-specific paths while preserving all augmented entries.
  • System prompt size: The SDK passes system_prompt as a --system-prompt CLI argument. Large CLAUDE.md files exceed Windows CreateProcessW's 32,768 char limit, causing ERROR_FILE_NOT_FOUND which the SDK misreports as "Claude Code not found". Now caps CLAUDE.md content on Windows to stay under the limit.
  • Cross-drive cwd: Agent processes were spawned with autoBuildSource (backend dir) as cwd. On Windows cross-drive setups (e.g., backend on C:, project on D:), this caused file access issues. Now uses projectPath as cwd since all script paths are absolute.

Changes

File Change
apps/frontend/src/main/agent/agent-process.ts Merge PATH entries from pythonEnv with augmented PATH instead of overwriting
apps/backend/core/client.py Cap CLAUDE.md content on Windows to prevent command-line length overflow
apps/frontend/src/main/agent/agent-manager.ts Use projectPath as cwd for spec creation, task execution, and QA spawns

Test plan

  • TypeScript compilation passes (no errors)
  • 55 agent tests pass (agent-process, agent-queue, env-utils)
  • 29 CLI tool manager tests pass
  • Python syntax validation passes
  • Pre-commit hooks pass (lint, typecheck, format)
  • Manual test on Windows with cross-drive project setup
  • Manual test with large CLAUDE.md (>15KB) on Windows

Closes #1661

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved Windows behavior by truncating oversized system-prompt content with a clear truncation notice and updated inclusion logs indicating truncated vs fully included content.
    • Ensured Python subprocesses run from the project directory and normalized/merged PATH entries so module and file resolution works reliably across platforms.
  • Tests

    • Updated integration tests to expect the new subprocess working-directory behavior.

…e cap, and cwd (#1661)

Three root causes addressed:

1. PATH overwrite: pythonEnv.PATH was overwriting the augmented PATH (with npm
   globals) in spawn env. Now merges PATH entries instead, prepending
   python-specific paths (pywin32_system32) while preserving all augmented entries.

2. System prompt size: On Windows, SDK passes system_prompt as --system-prompt
   CLI arg. Large CLAUDE.md files exceed CreateProcessW's 32,768 char limit,
   causing misleading "Claude Code not found" error. Now caps CLAUDE.md content
   on Windows to stay under the limit.

3. Cross-drive cwd: Agent processes were spawned with autoBuildSource as cwd.
   On Windows with cross-drive setups, this caused file access issues. Now uses
   projectPath as cwd since all script paths are absolute.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @AndyMik90, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers critical fixes for Windows users encountering "Claude CLI not found" errors. It comprehensively addresses three distinct root causes: incorrect handling of environment variable PATH merging, limitations on command-line argument length for system prompts, and cross-drive current working directory inconsistencies. These changes significantly enhance the robustness and reliability of agent processes on Windows.

Highlights

  • PATH overwrite resolution: Resolved an issue where pythonEnv.PATH would overwrite the augmented env.PATH on Windows, leading to "Claude code not found" errors. The fix now merges PATH entries by prepending Python-specific paths while preserving all augmented entries.
  • System prompt size limit for Windows: Addressed the Windows CreateProcessW 32,768 character limit for CLI arguments. Previously, large CLAUDE.md files could exceed this limit, causing ERROR_FILE_NOT_FOUND. The CLAUDE.md content is now capped on Windows to stay within the limit.
  • Cross-drive current working directory (cwd) fix: Fixed file access issues on Windows cross-drive setups by changing the current working directory (cwd) for spawned agent processes from autoBuildSource to projectPath. This ensures correct file access since all script paths are absolute.
Changelog
  • apps/backend/core/client.py
    • Capped the content of CLAUDE.md on Windows to prevent command-line length overflow when passed as a system prompt argument.
  • apps/frontend/src/main/agent/agent-manager.ts
    • Modified spawnProcess calls to use projectPath as the current working directory for spec creation, task execution, and QA processes.
  • apps/frontend/src/main/agent/agent-process.ts
    • Implemented logic to merge PATH entries from pythonEnv with the augmented PATH from env instead of overwriting, ensuring all necessary paths are preserved.
    • Imported getPathDelimiter from ../platform to correctly handle path separation based on the operating system.
Activity
  • The author, AndyMik90, created this pull request to address issue Agent error: Claude code not found (Kanban doesn't have access to files) #1661, focusing on resolving 'Claude CLI not found' errors on Windows.
  • The pull request includes a detailed summary, changes, and a test plan, indicating thorough preparation by the author.
  • The test plan outlines successful TypeScript compilation, agent tests, CLI tool manager tests, Python syntax validation, and pre-commit hooks, with manual tests for Windows cross-drive and large CLAUDE.md pending.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions bot added area/fullstack This is Frontend + Backend bug Something isn't working size/S Small (10-99 lines) labels Feb 15, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Windows-specific truncation for CLAUDE.md in the backend system prompt, changes frontend subprocesses to spawn with the project directory as cwd, and merges Python PATH entries into spawned Python process environments to preserve augmented PATH on Windows.

Changes

Cohort / File(s) Summary
Backend CLAUDE.md handling
apps/backend/core/client.py
Add WINDOWS_MAX_SYSTEM_PROMPT_CHARS and WINDOWS_TRUNCATION_MESSAGE; detect Windows and truncate CLAUDE.md when building the system prompt, insert truncation notice, and log/report truncation status.
Frontend subprocess cwd changes
apps/frontend/src/main/agent/agent-manager.ts, apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts
Use projectPath as cwd for spawnProcess calls (replacing autoBuildSource); update tests to expect projectPath as subprocess CWD to avoid Windows cross-drive access issues.
Frontend Python env PATH merge
apps/frontend/src/main/agent/agent-process.ts
Normalize PATH key casing, merge pythonEnv PATH entries into the augmented env PATH (prepend missing entries), and pass the merged env to the Python subprocess so previously-added PATH entries are preserved on Windows.

Sequence Diagram(s)

sequenceDiagram
  participant AgentMgr as Agent Manager
  participant AgentProc as Agent Process
  participant Python as Python subprocess
  participant FS as OS/filesystem

  AgentMgr->>AgentProc: spawnProcess(scriptPath, cwd=projectPath, env=env)
  AgentProc->>AgentProc: normalize PATH key casing\nbuild mergedPythonEnv (prepend missing pythonEnv paths)
  AgentProc->>Python: spawn with cwd=projectPath and env=mergedPythonEnv
  Python->>FS: resolve modules (sys.path[0], PATH)
  FS-->>Python: return files/modules
  Python-->>AgentProc: execution result
  AgentProc-->>AgentMgr: return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

os/windows, priority/medium, stable-roadmap, v2.7.6

Poem

🐰 I hopped through PATHs and nudged the CWD,
Trimmed a long CLAUDE prompt so Windows could see,
I wove in python paths so modules don't stray,
Subprocesses now find files and play,
A tiny rabbit fixed the way — hooray! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the three main issues being fixed (PATH, prompt size, cwd) on Windows, directly matching the primary changes in the changeset.
Linked Issues check ✅ Passed The PR addresses all three coding objectives from #1661: PATH entry merging in agent-process.ts, CLAUDE.md content capping in client.py, and projectPath cwd usage in agent-manager.ts.
Out of Scope Changes check ✅ Passed All changes directly address the three root causes identified in #1661; no extraneous modifications or unrelated features are introduced.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/1661-claude-code-not-found

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively addresses several critical Windows-specific issues that could cause "Claude code not found" errors. The fixes for PATH variable overwriting, command-line length limits, and cross-drive current working directory problems are all well-implemented and clearly explained. I have one suggestion to improve maintainability by replacing a magic number with a constant in apps/backend/core/client.py. Overall, these are excellent changes that will significantly improve the stability of the application on Windows.

Comment on lines 831 to 836
max_claude_md_chars = 24000 - len(base_prompt)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ "\n\n[... CLAUDE.md truncated due to Windows command-line length limit ...]"
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to truncate CLAUDE.md content on Windows is a good fix for the command-line length limit. To improve maintainability and readability, it would be better to define the magic number 24000 and the truncation message as constants.

You could define these at the top of the module:

WINDOWS_MAX_CMD_LINE_CHARS = 24000
TRUNCATION_MESSAGE = "\n\n[... CLAUDE.md truncated due to Windows command-line length limit ...]"

Then use them in the function as suggested.

Suggested change
max_claude_md_chars = 24000 - len(base_prompt)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ "\n\n[... CLAUDE.md truncated due to Windows command-line length limit ...]"
)
max_claude_md_chars = WINDOWS_MAX_CMD_LINE_CHARS - len(base_prompt)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ TRUNCATION_MESSAGE
)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/backend/core/client.py`:
- Around line 824-841: The current Windows truncation logic for
claude_md_content uses a fixed reserve (max_claude_md_chars = 24000 -
len(base_prompt)), which can still overflow when other ClaudeAgentOptions fields
(MCP servers, tools, settings path, etc.) are large; update the truncation to
(1) compute the reserved budget dynamically by serializing the other CLI
arguments (the fields used to build the command line from ClaudeAgentOptions)
and subtracting their length from the 32768 Windows limit, or alternatively use
a much more conservative cap (e.g., reserve 16000 chars for CLAUDE.md) so the
prompt cannot cause CreateProcessW to exceed 32768, and (2) prevent confusing
duplicate logs by making the "CLAUDE.md: included in system prompt" print
conditional (use an else branch or only print the included message when no
truncation occurred). Reference the truncation logic around is_windows(),
max_claude_md_chars, claude_md_content, and the two print statements.

@AndyMik90 AndyMik90 self-assigned this Feb 15, 2026
@AndyMik90
Copy link
Owner Author

🤖 Auto Claude PR Review

Merge Verdict: 🔴 BLOCKED

🔴 Blocked - 4 CI check(s) failing. Fix CI before merge.

Blocked: 4 CI check(s) failing. Fix CI before merge.

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

🚨 Blocking Issues (Must Fix)

  • CI Failed: CI Complete
  • CI Failed: test-frontend (macos-latest)
  • CI Failed: test-frontend (ubuntu-latest)
  • CI Failed: test-frontend (windows-latest)

Generated by Auto Claude PR Review


This review identified blockers that must be resolved before merge. Generated by Auto Claude.

- Extract magic number 24000 into WINDOWS_MAX_SYSTEM_PROMPT_CHARS constant
  (set to 20000 for more conservative ~12KB CLI headroom)
- Extract truncation suffix into WINDOWS_TRUNCATION_MESSAGE constant
- Fix double-print when truncation occurs: only print "included in system
  prompt" when CLAUDE.md was NOT truncated (was_truncated flag)
- Fix CI test failures: update subprocess-spawn tests to expect projectPath
  as cwd instead of autoBuildSource (matches the #1661 CWD change)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/backend/core/client.py`:
- Around line 843-848: The truncation appends WINDOWS_TRUNCATION_MESSAGE after
slicing to max_claude_md_chars, which causes the final claude_md_content to
exceed the WINDOWS_MAX_SYSTEM_PROMPT_CHARS budget; adjust the budget calculation
by subtracting len(WINDOWS_TRUNCATION_MESSAGE) as well. Change the logic around
max_claude_md_chars/claude_md_content to compute allowed =
WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt) -
len(WINDOWS_TRUNCATION_MESSAGE), ensure allowed > 0 before slicing, and then set
claude_md_content = claude_md_content[:allowed] + WINDOWS_TRUNCATION_MESSAGE (or
if allowed <= 0, set claude_md_content = WINDOWS_TRUNCATION_MESSAGE or an
appropriate fallback) so the final length always respects the system prompt
limit.

Comment on lines 843 to 848
max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ WINDOWS_TRUNCATION_MESSAGE
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Truncation message length not included in the budget calculation.

After truncation, the actual CLAUDE.md content length is max_claude_md_chars + len(WINDOWS_TRUNCATION_MESSAGE) (~70 extra chars). This slightly overshoots the budget. With ~12 KB headroom it's not a practical problem, but for correctness:

🔧 Suggested fix
-                max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt)
+                max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt) - len(WINDOWS_TRUNCATION_MESSAGE)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ WINDOWS_TRUNCATION_MESSAGE
)
max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt) - len(WINDOWS_TRUNCATION_MESSAGE)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
WINDOWS_TRUNCATION_MESSAGE
)
🤖 Prompt for AI Agents
In `@apps/backend/core/client.py` around lines 843 - 848, The truncation appends
WINDOWS_TRUNCATION_MESSAGE after slicing to max_claude_md_chars, which causes
the final claude_md_content to exceed the WINDOWS_MAX_SYSTEM_PROMPT_CHARS
budget; adjust the budget calculation by subtracting
len(WINDOWS_TRUNCATION_MESSAGE) as well. Change the logic around
max_claude_md_chars/claude_md_content to compute allowed =
WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt) -
len(WINDOWS_TRUNCATION_MESSAGE), ensure allowed > 0 before slicing, and then set
claude_md_content = claude_md_content[:allowed] + WINDOWS_TRUNCATION_MESSAGE (or
if allowed <= 0, set claude_md_content = WINDOWS_TRUNCATION_MESSAGE or an
appropriate fallback) so the final length always respects the system prompt
limit.

Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

🟠 Follow-up Review: Needs Revision

🟠 Needs revision - 2 blocking issue(s) require fixes.

Resolution Status

  • Resolved: 0 previous findings addressed
  • Unresolved: 0 previous findings remain
  • 🆕 New Issues: 4 new findings in recent changes

Finding Validation

  • 🔍 Dismissed as False Positives: 0 findings were re-investigated and found to be incorrect
  • Confirmed Valid: 3 findings verified as genuine issues
  • 👤 Needs Human Review: 0 findings require manual verification

🚨 Blocking Issues

  • quality: PATH merging selects wrong PATH key on Windows due to casing
  • quality: Duplicate PATH keys with different casings passed to child process on Windows

Verdict

CI status: ✅ All 20 CI checks passing (resolved from previous 4 failures — good progress). However, 2 medium-severity findings (NEW-001, NEW-002) in the new PATH merging code were confirmed valid by the finding-validator. Both relate to Windows PATH casing: getAugmentedEnv() can produce env objects with both Path (original) and PATH (augmented) keys on Windows. The new merge logic at line 689 uses Object.keys().find() which selects the non-augmented Path first (insertion order), and the final spread produces duplicate PATH keys with different values in the child process environment. The fix is straightforward: prefer uppercase PATH key and normalize to a single key before merging, similar to how python-env-manager.ts already handles this at lines 737-738. NEW-003 (low severity, truncation budget ~116 char overshoot) is confirmed valid but practically harmless given ~12KB headroom. CodeRabbit's concern about insufficient headroom (CMT-001) was already addressed by reducing the constant from 24000 to 20000.

Review Process

Agents invoked: new-code-reviewer, comment-analyzer, finding-validator


This is an AI-generated follow-up review using parallel specialist analysis with finding validation.

Findings (4 selected of 4 total)

🟡 [NEW-001] [MEDIUM] PATH merging selects wrong PATH key on Windows due to casing

📁 apps/frontend/src/main/agent/agent-process.ts:689

On Windows, getAugmentedEnv() produces an env object with both 'Path' (original system PATH from process.env spread) and 'PATH' (augmented paths only). The Object.keys(env).find(k => k.toUpperCase() === 'PATH') call returns 'Path' first (insertion order), so the merge logic uses the non-augmented system PATH as its base. This means augmented entries (npm globals, Claude CLI path, tool-specific paths) added by getAugmentedEnv() are discarded from the merged result, potentially causing 'Claude Code not found' on Windows setups where the claude CLI is only reachable via an augmented PATH entry.

Suggested fix:

Prefer the uppercase 'PATH' key since getAugmentedEnv() always writes to it:

const envPathKey = 'PATH' in env ? 'PATH' : (Object.keys(env).find(k => k.toUpperCase() === 'PATH') || 'PATH');

Alternatively, normalize the env object to a single PATH key before merging, similar to what getPythonEnv() already does at lines 737-738 of python-env-manager.ts.

🟡 [NEW-002] [MEDIUM] Duplicate PATH keys with different casings passed to child process on Windows

📁 apps/frontend/src/main/agent/agent-process.ts:711

When envPathKey (e.g., 'Path' from env) and pythonPathKey (e.g., 'PATH' from mergedPythonEnv) differ in casing, the final spread {...env, ...mergedPythonEnv} produces an env object with BOTH 'Path' and 'PATH' keys. mergedPythonEnv's 'PATH' overwrites env's 'PATH' but env's 'Path' persists. On Windows, CreateProcessW treats env vars case-insensitively, so which PATH value the child process actually uses is undefined. getPythonEnv() in python-env-manager.ts (lines 737-738) already handles this correctly by deleting the non-normalized key, but this new merge code does not.

Suggested fix:

After finding envPathKey, normalize to a single PATH key by deleting the stale variant from env before merging:

if (envPathKey !== 'PATH' && envPathKey in env) {
  env['PATH'] = env[envPathKey];
  delete env[envPathKey];
}

This follows the same pattern used in python-env-manager.ts lines 737-738.

🔵 [NEW-003] [LOW] Truncation budget does not account for appended overhead (~116 chars)

📁 apps/backend/core/client.py:843

The budget max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt) does not subtract the WINDOWS_TRUNCATION_MESSAGE length (~72 chars) or the header template '\n\n# Project Instructions (from CLAUDE.md)\n\n' (~44 chars). The final system prompt overshoots the 20,000-char target by ~116 characters. With ~12KB headroom to the 32,768 Windows CreateProcessW limit, this is practically inconsequential, but the budget calculation is subtly incorrect.

Suggested fix:

Subtract the overhead from the budget:

overhead = len(WINDOWS_TRUNCATION_MESSAGE) + len('\n\n# Project Instructions (from CLAUDE.md)\n\n')
max_claude_md_chars = WINDOWS_MAX_SYSTEM_PROMPT_CHARS - len(base_prompt) - overhead

🔵 [CMT-001] [LOW] [FROM COMMENTS] CodeRabbit concern about insufficient CLI overhead reserve - already addressed

📁 apps/backend/core/client.py:39

CodeRabbit flagged that the original 8KB reserve (when constant was 24000) may be insufficient for complex MCP configurations. This was already addressed in commit d646c84 by reducing the constant from 24000 to 20000, increasing headroom from ~8KB to ~12KB. No further action needed.


This review was generated by Auto Claude.

- Normalize env objects to a single uppercase 'PATH' key before merging
  to prevent duplicate PATH keys on Windows where process.env has 'Path'
  and getAugmentedEnv() writes 'PATH'. Without this, Object.keys().find()
  returns 'Path' first (insertion order), discarding augmented entries,
  and the final spread produces both 'Path' and 'PATH' keys.
  Follows the same pattern used in python-env-manager.ts. (#1661)

- Subtract WINDOWS_TRUNCATION_MESSAGE length from the truncation budget
  so the final system prompt stays within WINDOWS_MAX_SYSTEM_PROMPT_CHARS.

Addresses PR #1843 review findings NEW-001, NEW-002, NEW-003.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added size/M Medium (100-499 lines) and removed size/S Small (10-99 lines) labels Feb 16, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/backend/core/client.py`:
- Around line 836-859: The current Windows truncation logic fails when
max_claude_md_chars <= 0 and ends up appending the full claude_md_content;
update the block around is_windows()/max_claude_md_chars so that if
max_claude_md_chars <= 0 you do not append CLAUDE.md at all (set was_truncated =
True), print a clear message (e.g., "CLAUDE.md: omitted (no budget under Windows
command-line limit)"), and only append claude_md_content when
max_claude_md_chars > 0 (truncating when necessary with
WINDOWS_TRUNCATION_MESSAGE); reference is_windows,
WINDOWS_MAX_SYSTEM_PROMPT_CHARS, base_prompt, WINDOWS_TRUNCATION_MESSAGE,
claude_md_content, and was_truncated to locate where to change the logic and
messages.

In `@apps/frontend/src/main/agent/agent-process.ts`:
- Around line 726-733: The spawn call currently spreads env then mergedPythonEnv
so mergedPythonEnv unconditionally overrides keys from env (including PATH which
you purposely merged earlier), and setupProcessEnvironment() still injects
duplicate Python vars; remove the redundant PYTHON-specific assignments (e.g.,
PYTHONUNBUFFERED, PYTHONIOENCODING, PYTHONUTF8) from setupProcessEnvironment()
so getPythonEnv()/getMergedPythonEnv (the code producing mergedPythonEnv) is the
canonical source, or alternatively change the spawn merge to explicitly merge
Python keys the same way PATH is merged; also update the inline comment near the
spawn (where env, mergedPythonEnv, oauthModeClearVars, apiProfileEnv are
combined) to clearly state that mergedPythonEnv has final precedence for
Python-related vars and PATH merging is preserved.

Comment on lines 836 to 859
# On Windows, the SDK passes system_prompt as a --system-prompt CLI argument.
# Windows CreateProcessW has a 32,768 character limit for the entire command line.
# When CLAUDE.md is very large, the command can exceed this limit, causing Windows
# to return ERROR_FILE_NOT_FOUND which the SDK misreports as "Claude Code not found".
# Cap CLAUDE.md content to keep total command line under the limit. (#1661)
was_truncated = False
if is_windows():
max_claude_md_chars = (
WINDOWS_MAX_SYSTEM_PROMPT_CHARS
- len(base_prompt)
- len(WINDOWS_TRUNCATION_MESSAGE)
)
if len(claude_md_content) > max_claude_md_chars > 0:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ WINDOWS_TRUNCATION_MESSAGE
)
print(
" - CLAUDE.md: truncated (exceeded Windows command-line limit)"
)
was_truncated = True
base_prompt = f"{base_prompt}\n\n# Project Instructions (from CLAUDE.md)\n\n{claude_md_content}"
print(" - CLAUDE.md: included in system prompt")
if not was_truncated:
print(" - CLAUDE.md: included in system prompt")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Edge case: when max_claude_md_chars <= 0, full CLAUDE.md is included untruncated.

If base_prompt + WINDOWS_TRUNCATION_MESSAGE already exceeds WINDOWS_MAX_SYSTEM_PROMPT_CHARS, the > 0 guard skips truncation and the entire CLAUDE.md is appended — which will definitely exceed the Windows limit. While base_prompt is currently short (~400 chars), this is a latent bug if the prompt grows.

Proposed fix: omit CLAUDE.md when budget is exhausted
             if is_windows():
                 max_claude_md_chars = (
                     WINDOWS_MAX_SYSTEM_PROMPT_CHARS
                     - len(base_prompt)
                     - len(WINDOWS_TRUNCATION_MESSAGE)
                 )
-                if len(claude_md_content) > max_claude_md_chars > 0:
+                if max_claude_md_chars <= 0:
+                    claude_md_content = ""
+                    print(
+                        "   - CLAUDE.md: omitted (base prompt already near Windows limit)"
+                    )
+                    was_truncated = True
+                elif len(claude_md_content) > max_claude_md_chars:
                     claude_md_content = (
                         claude_md_content[:max_claude_md_chars]
                         + WINDOWS_TRUNCATION_MESSAGE
                     )
🤖 Prompt for AI Agents
In `@apps/backend/core/client.py` around lines 836 - 859, The current Windows
truncation logic fails when max_claude_md_chars <= 0 and ends up appending the
full claude_md_content; update the block around is_windows()/max_claude_md_chars
so that if max_claude_md_chars <= 0 you do not append CLAUDE.md at all (set
was_truncated = True), print a clear message (e.g., "CLAUDE.md: omitted (no
budget under Windows command-line limit)"), and only append claude_md_content
when max_claude_md_chars > 0 (truncating when necessary with
WINDOWS_TRUNCATION_MESSAGE); reference is_windows,
WINDOWS_MAX_SYSTEM_PROMPT_CHARS, base_prompt, WINDOWS_TRUNCATION_MESSAGE,
claude_md_content, and was_truncated to locate where to change the logic and
messages.

Comment on lines 726 to 733
childProcess = spawn(pythonCommand, [...pythonBaseArgs, ...args], {
cwd,
env: {
...env, // Already includes process.env, extraEnv, profileEnv, PYTHONUNBUFFERED, PYTHONUTF8
...pythonEnv, // Include Python environment (PYTHONPATH for bundled packages)
...mergedPythonEnv, // Python env with merged PATH (preserves augmented PATH entries)
...oauthModeClearVars, // Clear stale ANTHROPIC_* vars when in OAuth mode
...apiProfileEnv // Include active API profile config (highest priority for ANTHROPIC_* vars)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find pythonEnvManager.getPythonEnv() calls and implementation
rg -n "getPythonEnv" --type=ts -A5 -B5 | head -100

Repository: AndyMik90/Auto-Claude

Length of output: 10363


🏁 Script executed:

#!/bin/bash
# Look for pythonEnvManager definition and initialization
rg -n "pythonEnvManager\s*=" --type=ts -A3 -B3

Repository: AndyMik90/Auto-Claude

Length of output: 615


🏁 Script executed:

#!/bin/bash
# Check the file where pythonEnvManager is defined
fd pythonEnvManager --type=ts

Repository: AndyMik90/Auto-Claude

Length of output: 234


🏁 Script executed:

#!/bin/bash
# Read the getPythonEnv() method implementation
sed -n '690,750p' apps/frontend/src/main/python-env-manager.ts

Repository: AndyMik90/Auto-Claude

Length of output: 3204


🏁 Script executed:

#!/bin/bash
# Read more of the getPythonEnv() implementation to see all returned keys
sed -n '690,800p' apps/frontend/src/main/python-env-manager.ts

Repository: AndyMik90/Auto-Claude

Length of output: 4692


🏁 Script executed:

#!/bin/bash
# Look at agent-process.ts to see mergedPythonEnv construction and context
sed -n '700,750p' apps/frontend/src/main/agent/agent-process.ts

Repository: AndyMik90/Auto-Claude

Length of output: 2573


🏁 Script executed:

#!/bin/bash
# Look at env construction before it's passed to spawn
sed -n '650,730p' apps/frontend/src/main/agent/agent-process.ts | head -100

Repository: AndyMik90/Auto-Claude

Length of output: 3992


🏁 Script executed:

#!/bin/bash
# Check what extraEnv, profileEnv, and other env components contain
rg -n "extraEnv|profileEnv|oauthModeClearVars" apps/frontend/src/main/agent/agent-process.ts -B2 -A2 | head -80

Repository: AndyMik90/Auto-Claude

Length of output: 3624


🏁 Script executed:

#!/bin/bash
# Check setupProcessEnvironment to see what's set in env
sed -n '176,260p' apps/frontend/src/main/agent/agent-process.ts

Repository: AndyMik90/Auto-Claude

Length of output: 4017


Clarify redundant Python environment variable overrides and document override semantics.

mergedPythonEnv spreads after env (line 730), causing all keys to override env values. PATH is explicitly merged (lines 706-721) to preserve augmented entries, but other keys override unconditionally: PYTHONUNBUFFERED, PYTHONIOENCODING, and PYTHONUTF8 are redundantly set in both env and mergedPythonEnv. While new keys like PYTHONDONTWRITEBYTECODE and PYTHONNOUSERSITE should override consistently, remove the redundant duplication from setupProcessEnvironment() (lines 242-244) since getPythonEnv() now provides the canonical Python configuration. Update the comment on line 730 to document this override behavior or consider an explicit merge strategy for all Python-related keys to match PATH handling.

🤖 Prompt for AI Agents
In `@apps/frontend/src/main/agent/agent-process.ts` around lines 726 - 733, The
spawn call currently spreads env then mergedPythonEnv so mergedPythonEnv
unconditionally overrides keys from env (including PATH which you purposely
merged earlier), and setupProcessEnvironment() still injects duplicate Python
vars; remove the redundant PYTHON-specific assignments (e.g., PYTHONUNBUFFERED,
PYTHONIOENCODING, PYTHONUTF8) from setupProcessEnvironment() so
getPythonEnv()/getMergedPythonEnv (the code producing mergedPythonEnv) is the
canonical source, or alternatively change the spawn merge to explicitly merge
Python keys the same way PATH is merged; also update the inline comment near the
spawn (where env, mergedPythonEnv, oauthModeClearVars, apiProfileEnv are
combined) to clearly state that mergedPythonEnv has final precedence for
Python-related vars and PATH merging is preserved.

…ation budget

- Finding 1 (MEDIUM): Prefer 'PATH' key directly when present in env to avoid
  insertion-order bug where Object.keys().find() returned 'Path' first on Windows
- Finding 2 (MEDIUM): Normalization block (delete stale cased key, write 'PATH')
  already in place from previous commit; Finding 1 fix ensures envPathKey resolves
  correctly so normalization fires only when truly needed
- Finding 3 (LOW): Subtract header template overhead from max_claude_md_chars to
  prevent ~44-char overshoot in Windows command-line truncation budget (#1661)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/frontend/src/main/agent/agent-process.ts`:
- Around line 707-720: The current PATH dedup logic for mergedPythonEnv['PATH']
uses Set.has() which is case-sensitive and can leave duplicate entries on
Windows; update the comparison to normalize path entries when building
augmentedPathEntries and when filtering pythonPathEntries (e.g., on
process.platform === 'win32' use entry.toLowerCase() and optionally
path.normalize()) so comparisons are case-insensitive on Windows while
preserving original entry casing in the final mergedPythonEnv['PATH']; apply
this change around the augmentedPathEntries and pythonPathEntries construction
in the agent-process PATH merge block.
- Around line 690-698: The PATH normalization currently short-circuits when
'PATH' already exists and misses removing other-cased keys (e.g., 'Path'), so
update setupProcessEnvironment to find all env keys where key.toUpperCase() ===
'PATH', consolidate their value into a single uppercase 'PATH' entry (prefer the
existing 'PATH' value or merge/append as appropriate), then delete all other
keys whose uppercased name is 'PATH' so only 'PATH' remains; operate on the
local env object referenced in the function (the env variable and envPathKey
logic) before the spawn() call that uses this env.

---

Duplicate comments:
In `@apps/backend/core/client.py`:
- Around line 849-857: The chained comparison allows skipping truncation when
max_claude_md_chars <= 0; update the logic around claude_md_content to treat a
non-positive max_claude_md_chars as an exhausted budget and truncate
accordingly: if max_claude_md_chars > 0, truncate to that length and append
WINDOWS_TRUNCATION_MESSAGE when len(claude_md_content) exceeds it; if
max_claude_md_chars <= 0, replace claude_md_content with only
WINDOWS_TRUNCATION_MESSAGE (or an empty placeholder) and set was_truncated =
True and print the same truncation message; reference claude_md_content,
max_claude_md_chars, WINDOWS_TRUNCATION_MESSAGE, and
WINDOWS_MAX_SYSTEM_PROMPT_CHARS when applying the change.

Comment on lines 707 to 720
if (mergedPythonEnv['PATH'] && env['PATH']) {
const augmentedPathEntries = new Set(
(env['PATH'] as string).split(pathSep).filter(Boolean)
);
// Extract only new entries from pythonEnv.PATH that aren't already in the augmented PATH
const pythonPathEntries = (mergedPythonEnv['PATH'] as string)
.split(pathSep)
.filter(entry => entry && !augmentedPathEntries.has(entry));

// Prepend python-specific paths (e.g., pywin32_system32) to the augmented PATH
mergedPythonEnv['PATH'] = pythonPathEntries.length > 0
? [...pythonPathEntries, env['PATH'] as string].join(pathSep)
: env['PATH'] as string;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider case-insensitive PATH entry deduplication on Windows.

Line 714 uses strict string equality via Set.has(). On Windows, path entries are case-insensitive (C:\Python39 vs c:\python39), so the same directory could appear twice. This won't break anything but produces a slightly bloated PATH.

♻️ Optional: normalize entries for comparison on Windows
      const augmentedPathEntries = new Set(
-       (env['PATH'] as string).split(pathSep).filter(Boolean)
+       (env['PATH'] as string).split(pathSep).filter(Boolean).map(e => isWindows() ? e.toLowerCase() : e)
      );
      // Extract only new entries from pythonEnv.PATH that aren't already in the augmented PATH
      const pythonPathEntries = (mergedPythonEnv['PATH'] as string)
        .split(pathSep)
-       .filter(entry => entry && !augmentedPathEntries.has(entry));
+       .filter(entry => entry && !augmentedPathEntries.has(isWindows() ? entry.toLowerCase() : entry));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/main/agent/agent-process.ts` around lines 707 - 720, The
current PATH dedup logic for mergedPythonEnv['PATH'] uses Set.has() which is
case-sensitive and can leave duplicate entries on Windows; update the comparison
to normalize path entries when building augmentedPathEntries and when filtering
pythonPathEntries (e.g., on process.platform === 'win32' use entry.toLowerCase()
and optionally path.normalize()) so comparisons are case-insensitive on Windows
while preserving original entry casing in the final mergedPythonEnv['PATH'];
apply this change around the augmentedPathEntries and pythonPathEntries
construction in the agent-process PATH merge block.

Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

Merge Verdict: 🟠 NEEDS REVISION

🟠 Needs revision - 1 issue(s) require attention.

1 issue(s) must be addressed (0 required, 1 recommended), 1 suggestions

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

Findings Summary

  • Medium: 1 issue(s)
  • Low: 1 issue(s)

Generated by Auto Claude PR Review

Findings (2 selected of 2 total)

🟡 [a6e21d8cbc29] [MEDIUM] No unit tests for Windows PATH merge logic

📁 apps/frontend/src/main/agent/agent-process.ts:682

The new PATH merge logic (lines 682-720) is 40 lines of cross-platform code handling case normalization, key deduplication, and entry merging. The existing test mock (getPythonEnv: vi.fn(() => ({})) at agent-process.test.ts:108) returns an empty object, so the PATH merge branch where mergedPythonEnv['PATH'] exists is never exercised. Key untested scenarios: (1) pythonEnv has 'Path' key (Windows-style) that should be normalized to 'PATH', (2) env has both 'Path' and 'PATH' keys, (3) pythonEnv PATH entries that overlap with augmented PATH are deduplicated, (4) pythonEnv-specific entries are prepended. Given this is Windows-critical bug-fix code, unit tests would catch regressions. | The 40-line PATH merge block (lines 682-720) is added to the spawnProcess method, which already spans 337 lines (626-963). While the new code is well-commented and logically coherent, extracting it to a dedicated helper function (e.g., mergePythonEnvPath(env, pythonEnv, pathSep)) would improve both readability and testability. The helper could be unit-tested independently without needing to mock the entire spawn setup.

Suggested fix:

Add test cases to agent-process.test.ts that mock getPythonEnv to return objects with PATH entries (including Windows-style 'Path' key) and verify the spawned env contains the merged PATH with python entries prepended and augmented entries preserved.

🔵 [a64990385f7c] [LOW] Duplicated PATH key normalization pattern across two modules

📁 apps/frontend/src/main/agent/agent-process.ts:690

The PATH key case-normalization logic in agent-process.ts (lines 690-704) duplicates a nearly identical pattern in python-env-manager.ts (lines 729-748). Both modules: (1) find the PATH key case-insensitively via Object.keys(env).find(k => k.toUpperCase() === 'PATH'), (2) normalize to uppercase 'PATH', and (3) delete the old case-variant key. Searched Grep('toUpperCase.*PATH', 'apps/frontend/src/main') - confirmed both implementations exist. This is acceptable in a focused bug fix PR, but a shared utility like normalizePathKey(env) in the platform module would reduce duplication. The root cause is that getAugmentedEnv() (env-utils.ts:236) spreads process.env (producing 'Path' on Windows) then writes to 'PATH' (line 277), creating both keys — a source-level fix there would eliminate the need for downstream normalization entirely.

Suggested fix:

Consider extracting a shared normalizeEnvPathKey(env) utility in apps/frontend/src/main/platform/index.ts that both agent-process.ts and python-env-manager.ts can reuse. Alternatively, fix getAugmentedEnv() to normalize the PATH key at the source, eliminating the need for downstream normalization.

This review was generated by Auto Claude.

When getAugmentedEnv() spreads process.env on Windows, the resulting object
contains both 'Path' (from process.env spread) and 'PATH' (explicitly written
by getAugmentedEnv). The prior normalization block only removed non-'PATH' keys
when 'PATH' was absent, leaving the stale 'Path' key when both coexisted.

Add a cleanup loop to delete all case-variant PATH keys that differ from
'PATH' after the main normalization, ensuring the child process inherits a
single canonical 'PATH' entry with the fully-augmented value. (#1661)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/frontend/src/main/agent/agent-process.ts`:
- Around line 716-729: The PATH dedup logic doesn't account for Windows
case-insensitivity so entries like "C:\Python39" and "c:\python39" can both
appear; update the logic in agent-process.ts where augmentedPathEntries and
pythonPathEntries are built to normalize entries to a consistent case on Windows
(e.g., map entries to .toLowerCase() when process.platform === 'win32') and use
that normalized value for Set.has checks and filtering while preserving the
original-cased entries when reconstructing mergedPythonEnv['PATH'] (use the
normalized set for membership tests but keep the original entry strings when
building pythonPathEntries and final PATH).

Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

🟠 Follow-up Review: Needs Revision

🟠 Needs revision - 2 unresolved finding(s) from previous review.

Resolution Status

  • Resolved: 0 previous findings addressed
  • Unresolved: 2 previous findings remain
  • 🆕 New Issues: 1 new findings in recent changes

Finding Validation

  • 🔍 Dismissed as False Positives: 1 findings were re-investigated and found to be incorrect
  • Confirmed Valid: 3 findings verified as genuine issues
  • 👤 Needs Human Review: 0 findings require manual verification

🚨 Blocking Issues

  • quality: PATH normalization missing in agent-queue.ts
  • quality: [UNRESOLVED] No unit tests for Windows PATH merge logic

Verdict

[Recovered via extraction] CI: All 20 checks passing. Two MEDIUM findings remain confirmed valid (missing unit tests and PATH normalization missing in agent-queue.ts), plus one LOW finding (duplicated normalization). One LOW finding was dismissed as a false positive with no functional impact.

Review Process

Agents invoked: resolution-verifier, new-code-reviewer, comment-analyzer, finding-validator


This is an AI-generated follow-up review using parallel specialist analysis with finding validation.

Findings (3 selected of 3 total)

🟡 [FU-F6AE6259] [MEDIUM] PATH normalization missing in agent-queue.ts

📁 apps/frontend/src/main/agent/agent-queue.ts:0

[Recovered via extraction] PATH normalization missing in agent-queue.ts

🟡 [a6e21d8cbc29] [MEDIUM] [UNRESOLVED] No unit tests for Windows PATH merge logic

📁 apps/frontend/src/main/agent/agent-process.ts:682

The new PATH merge logic (lines 682-720) is 40 lines of cross-platform code handling case normalization, key deduplication, and entry merging. The existing test mock (getPythonEnv: vi.fn(() => ({})) at agent-process.test.ts:108) returns an empty object, so the PATH merge branch where mergedPythonEnv['PATH'] exists is never exercised. Key untested scenarios: (1) pythonEnv has 'Path' key (Windows-style) that should be normalized to 'PATH', (2) env has both 'Path' and 'PATH' keys, (3) pythonEnv PATH entries that overlap with augmented PATH are deduplicated, (4) pythonEnv-specific entries are prepended. Given this is Windows-critical bug-fix code, unit tests would catch regressions. | The 40-line PATH merge block (lines 682-720) is added to the spawnProcess method, which already spans 337 lines (626-963). While the new code is well-commented and logically coherent, extracting it to a dedicated helper function (e.g., mergePythonEnvPath(env, pythonEnv, pathSep)) would improve both readability and testability. The helper could be unit-tested independently without needing to mock the entire spawn setup.

Suggested fix:

Add test cases to agent-process.test.ts that mock getPythonEnv to return objects with PATH entries (including Windows-style 'Path' key) and verify the spawned env contains the merged PATH with python entries prepended and augmented entries preserved.

🔵 [a64990385f7c] [LOW] [UNRESOLVED] Duplicated PATH key normalization pattern across two modules

📁 apps/frontend/src/main/agent/agent-process.ts:690

The PATH key case-normalization logic in agent-process.ts (lines 690-704) duplicates a nearly identical pattern in python-env-manager.ts (lines 729-748). Both modules: (1) find the PATH key case-insensitively via Object.keys(env).find(k => k.toUpperCase() === 'PATH'), (2) normalize to uppercase 'PATH', and (3) delete the old case-variant key. Searched Grep('toUpperCase.*PATH', 'apps/frontend/src/main') - confirmed both implementations exist. This is acceptable in a focused bug fix PR, but a shared utility like normalizePathKey(env) in the platform module would reduce duplication. The root cause is that getAugmentedEnv() (env-utils.ts:236) spreads process.env (producing 'Path' on Windows) then writes to 'PATH' (line 277), creating both keys — a source-level fix there would eliminate the need for downstream normalization entirely.

Suggested fix:

Consider extracting a shared normalizeEnvPathKey(env) utility in apps/frontend/src/main/platform/index.ts that both agent-process.ts and python-env-manager.ts can reuse. Alternatively, fix getAugmentedEnv() to normalize the PATH key at the source, eliminating the need for downstream normalization.

This review was generated by Auto Claude.

- Extract normalizeEnvPathKey() and mergePythonEnvPath() into env-utils.ts
  as shared, exported helpers to eliminate duplicated PATH key case-normalization
  logic across agent-process.ts and python-env-manager.ts (Finding 3)
- Add PATH normalization call in agent-queue.ts spawnIdeationProcess and
  spawnRoadmapProcess to fix the same Windows PATH duplicate-key issue that
  was fixed in agent-process.ts (#1661) (Finding 1)
- Add comprehensive unit tests for normalizeEnvPathKey() and mergePythonEnvPath()
  covering Windows-style 'Path' key renaming, duplicate key removal, PATH
  deduplication across merge, and Unix separator support (Finding 2)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
import { readSettingsFile } from '../settings-utils';
import type { AppSettings } from '../../shared/types/settings';
import { getOAuthModeClearVars } from './env-utils';
import { getOAuthModeClearVars, normalizeEnvPathKey, mergePythonEnvPath } from './env-utils';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import normalizeEnvPathKey.

Copilot Autofix

AI 1 day ago

In general, to fix an unused import, remove the unused symbol from the import clause, or, if all imported symbols are unused, remove the entire import statement. This avoids confusion and keeps the module’s dependency surface minimal.

Here, only normalizeEnvPathKey is reported unused in the import from ./env-utils on line 25, while getOAuthModeClearVars and mergePythonEnvPath may still be used elsewhere in the file. The safest change is to edit that specific import line in apps/frontend/src/main/agent/agent-process.ts to drop normalizeEnvPathKey and leave the other imports intact. No additional methods, definitions, or new imports are required, and no runtime behavior should change.

Concretely:

  • In apps/frontend/src/main/agent/agent-process.ts, locate the import on line 25.
  • Remove normalizeEnvPathKey from the destructured import list.
  • Leave all other code untouched.
Suggested changeset 1
apps/frontend/src/main/agent/agent-process.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/frontend/src/main/agent/agent-process.ts b/apps/frontend/src/main/agent/agent-process.ts
--- a/apps/frontend/src/main/agent/agent-process.ts
+++ b/apps/frontend/src/main/agent/agent-process.ts
@@ -22,7 +22,7 @@
 import { buildMemoryEnvVars } from '../memory-env-builder';
 import { readSettingsFile } from '../settings-utils';
 import type { AppSettings } from '../../shared/types/settings';
-import { getOAuthModeClearVars, normalizeEnvPathKey, mergePythonEnvPath } from './env-utils';
+import { getOAuthModeClearVars, mergePythonEnvPath } from './env-utils';
 import { getAugmentedEnv } from '../env-utils';
 import { getToolInfo, getClaudeCliPathForSdk } from '../cli-tool-manager';
 import { killProcessGracefully, isWindows, getPathDelimiter } from '../platform';
EOF
@@ -22,7 +22,7 @@
import { buildMemoryEnvVars } from '../memory-env-builder';
import { readSettingsFile } from '../settings-utils';
import type { AppSettings } from '../../shared/types/settings';
import { getOAuthModeClearVars, normalizeEnvPathKey, mergePythonEnvPath } from './env-utils';
import { getOAuthModeClearVars, mergePythonEnvPath } from './env-utils';
import { getAugmentedEnv } from '../env-utils';
import { getToolInfo, getClaudeCliPathForSdk } from '../cli-tool-manager';
import { killProcessGracefully, isWindows, getPathDelimiter } from '../platform';
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto Claude Review - APPROVED

Status: Ready to Merge

Summary: ## ✅ Follow-up Review: Ready To Merge

✅ Ready to merge - All checks passing and findings addressed.

Resolution Status

  • Resolved: 0 previous findings addressed
  • Unresolved: 0 previous findings remain
  • 🆕 New Issues: 0 new findings in recent changes

Finding Validation

  • 🔍 Dismissed as False Positives: 0 findings were re-investigated and found to be incorrect
  • Confirmed Valid: 3 findings verified as genuine issues
  • 👤 Needs Human Review: 0 findings require manual verification

Verdict

[Recovered via extraction] All 3 previous findings are resolved. 4 new findings identified, all LOW severity. CI is fully green with all 20 checks passing. No blocking issues remain.

Review Process

Agents invoked: resolution-verifier, new-code-reviewer, comment-analyzer, finding-validator


This is an AI-generated follow-up review using parallel specialist analysis with finding validation.


This automated review found no blocking issues. The PR can be safely merged.

Generated by Auto Claude

)
print(
" - CLAUDE.md: truncated (exceeded Windows command-line limit)"
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The CLAUDE.md truncation logic can be bypassed on Windows if max_claude_md_chars becomes negative, causing the > 0 check in the if condition to fail.
Severity: CRITICAL

Suggested Fix

Modify the conditional logic to handle cases where max_claude_md_chars is not positive. For example, change the check to if max_claude_md_chars < len(claude_md_content): and ensure max_claude_md_chars is clamped at a minimum of 0 before being used for slicing, preventing negative budget issues.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/backend/core/client.py#L856

Potential issue: On Windows, the calculation for `max_claude_md_chars` can result in a
negative value if the `base_prompt` is sufficiently large. The conditional check `if
len(claude_md_content) > max_claude_md_chars > 0:` requires `max_claude_md_chars` to be
positive. When it's negative, the check fails, and the truncation logic is skipped
entirely. This allows the total system prompt to exceed the Windows `CreateProcessW`
character limit, leading to a failure that the SDK misreports as "Claude Code not
found," which is the exact bug this change was intended to fix.

Did we get this right? 👍 / 👎 to inform future reviews.

@AndyMik90 AndyMik90 merged commit 76d1d3b into develop Feb 18, 2026
20 checks passed
@AndyMik90 AndyMik90 deleted the fix/1661-claude-code-not-found branch February 18, 2026 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/fullstack This is Frontend + Backend bug Something isn't working size/M Medium (100-499 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent error: Claude code not found (Kanban doesn't have access to files)

1 participant